package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.injector.methods.UpdateById;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.feign.ApBehaviorEntryFegin;
import com.heima.article.feign.UserFeign;
import com.heima.article.mapper.*;
import com.heima.article.service.ApArticleContentService;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.ApCollectionService;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.datos.ArticelDto;
import com.heima.model.article.datos.ArticleHomeDto;
import com.heima.model.article.datos.ArticleInfoDto;
import com.heima.model.article.pojos.*;
import com.heima.model.article.vo.HotArticleVo;
import com.heima.model.behavior.pojos.ApBehaviorEntry;
import com.heima.model.behavior.pojos.ApLikesBehavior;
import com.heima.model.behavior.pojos.ApUnlikesBehavior;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.ArticleVisitStreamMess;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.user.pojos.ApUserFollow;
import com.heima.utils.threadlocal.AppThreadLocalUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.*;


@Service
@Transactional
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    private AuthorMapper authorMapper;
    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public ResponseResult saveApArtice(ArticelDto articelDto) {
        if (articelDto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        ApArticle apArticle = new ApArticle();
        BeanUtils.copyProperties(articelDto, apArticle);
        if (apArticle.getId() == null) {
            LambdaQueryWrapper<ApAuthor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(ApAuthor::getName, articelDto.getAuthorName());
            ApAuthor apAuthor = authorMapper.selectOne(lambdaQueryWrapper);
            if (apAuthor != null) {
                apArticle.setAuthorId((long) apAuthor.getId());
            }
            save(apArticle);
            ApArticleConfig articleConfig = new ApArticleConfig();
            articleConfig.setArticleId(apArticle.getId());
            articleConfig.setIsComment(true);
            articleConfig.setIsDelete(false);
            articleConfig.setIsDown(false);
            articleConfig.setIsForward(true);
            apArticleConfigMapper.insert(articleConfig);

            ApArticleContent apArticleContent = new ApArticleContent();
            apArticleContent.setContent(articelDto.getContent());
            apArticleContent.setArticleId(apArticle.getId());
            apArticleContentMapper.insert(apArticleContent);
        } else {
            ApArticle dbArticle = getById(articelDto.getId());
            if (dbArticle == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章没有找到");
            }
            updateById(dbArticle);
            ApArticleContent articleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, articelDto.getId()));
            articleContent.setContent(articelDto.getContent());
            apArticleContentMapper.updateById(articleContent);
        }
        //将文章信息保存到es
        saveArticle4Search(apArticle);

        return ResponseResult.okResult(apArticle.getId());
    }

    private void saveArticle4Search(ApArticle apArticle) {
        Map<String,Object> map = new HashMap<>();
        map.put("id",apArticle.getId());
        map.put("publishTime", apArticle.getPublishTime());
        map.put("layout", apArticle.getLayout());
        map.put("images", apArticle.getImages());
        map.put("authorId", apArticle.getAuthorId());
        map.put("title", apArticle.getTitle());
        IndexRequest indexRequest = new IndexRequest("app_info_article");
        indexRequest.id(apArticle.getId()+"");
        String s = JSON.toJSONString(map);
        indexRequest.source(s,XContentType.JSON);
        try {
            restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 单页最大加载的数字
    private final static short MAX_PAGE_SIZE = 50;
    @Autowired
    private ApArticleMapper apArticleMapper;

    @Value("${fdfs.url}")
    private String fileServerUrl;

    @Override
    public ResponseResult loadArticleList(ArticleHomeDto dto, Short type) {

        Integer size = dto.getSize();
        if (size == null || size == 0) {
            size = 10;
        }
        size = Math.min(dto.getSize(), MAX_PAGE_SIZE);
        dto.setSize(size);

        if (!type.equals(ArticleConstants.LOADTYPE_LOAD_MORE) && !type.equals(ArticleConstants.LOADTYPE_LOAD_NEW)) {
            type=ArticleConstants.LOADTYPE_LOAD_MORE;
        }

        if (StringUtils.isBlank(dto.getTag())) {
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }
        if (dto.getMaxBehotTime() == null) {
            dto.setMaxBehotTime(new Date());
        }
        if (dto.getMinBehotTime() == null) {
            dto.setMinBehotTime(new Date());
        }

        List<ApArticle> apArticleList = apArticleMapper.loadArticleList(dto, type);
        ResponseResult responseResult = ResponseResult.okResult(apArticleList);
        responseResult.setHost(fileServerUrl);
        return responseResult;

    }

    @Override
    public ResponseResult loadArticleInfo(ArticleInfoDto dto) {

        if (dto==null||dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询文章配置
        ApArticleConfig apArticleConfig = apArticleConfigMapper.selectOne(Wrappers.<ApArticleConfig>lambdaQuery()
                .eq(ApArticleConfig::getArticleId, dto.getArticleId()));
        if (apArticleConfig == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询文章内容
        ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery()
                .eq(ApArticleContent::getArticleId, dto.getArticleId()));
        if (apArticleContent == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
            Map<String, Object> map = new HashMap<>();
        map.put("config",apArticleConfig);
        map.put("content",apArticleContent);

        return ResponseResult.okResult(map);
    }
    @Autowired
    private ApBehaviorEntryFegin apBehaviorEntryFegin;

    @Autowired
    private UserFeign userFeign;
    @Autowired
    private ApCollectionMapper apCollectionMapper;

    @Override
    public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
        if (dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST);
        }
        boolean isLike=false,isUnLike=true,isFollow=false,isCollection=false;
        //查询实体
        ApBehaviorEntry apBehaviorEntry = apBehaviorEntryFegin.findByUserIdOrEquipmentId(user.getId(), dto.getEquipmentId());

        if (apBehaviorEntry == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询点赞
        ApLikesBehavior apLikesBehavior = apBehaviorEntryFegin.findLikeByArticleIdAndEntryId( dto.getArticleId(),apBehaviorEntry.getId(), ApLikesBehavior.Type.ARTICLE.getCode());
        if (apLikesBehavior != null && apLikesBehavior.getOperation().equals(ApLikesBehavior.Operation.LIKE.getCode())) {
            isLike=true;
        }
        //查询不喜欢
        ApUnlikesBehavior apUnlikesBehavior = apBehaviorEntryFegin.findUnLikeByArticleIdAndEntryId(apBehaviorEntry.getId(), dto.getArticleId());
        if (apUnlikesBehavior != null&&apUnlikesBehavior.getType().equals(ApUnlikesBehavior.Type.UNLIKE.getCode())) {
            isUnLike=false;
        }

        ApAuthor apAuthor = authorMapper.selectOne(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getId, dto.getAuthorId()));
        if (apAuthor != null) {
            //关注
            ApUserFollow apUserFollow = userFeign.findByUserIdAndFollowId(user.getId(),apAuthor.getUserId());
            if (apUserFollow != null ) {
                isFollow = true;
            }
        }

        //收藏
        ApCollection apCollection = apCollectionMapper.selectOne(Wrappers.<ApCollection>lambdaQuery()
                .eq(ApCollection::getArticleId, dto.getArticleId())
                .eq(ApCollection::getEntryId, apBehaviorEntry.getId()));
        if (apCollection != null) {
            isCollection=true;
        }
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("isfollow",isFollow);
        resultMap.put("islike",isLike);
        resultMap.put("isunlike",isUnLike);
        resultMap.put("iscollection",isCollection);
        return ResponseResult.okResult(resultMap);

    }
    /**
     * 重新计算文章分值
     * @param mess
     */
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public void updateApArticle(ArticleVisitStreamMess mess) {
        //查询文章
        ApArticle apArticle = getById(mess.getArticleId());
        //修改文章
       apArticle.setLikes(apArticle.getLikes()==null ? 0: (int) (apArticle.getLikes() + mess.getLike()));
       apArticle.setComment(apArticle.getComment()==null ? 0: (int) (apArticle.getComment() + mess.getComment()));
       apArticle.setCollection(apArticle.getCollection()==null ? 0: (int) (apArticle.getCollection() + mess.getCollect()));
       apArticle.setViews(apArticle.getViews()==null ? 0: (int) (apArticle.getViews() + mess.getView()));
        updateById(apArticle);

        //修改分数
        Integer sorce = changeSorce(apArticle);
        sorce=sorce*3;

        //修改缓存中的数据
        String articleStr = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());
        changeRedis(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId(),sorce,apArticle,articleStr);
        //推荐页修改缓存数据
        String articleStrAll = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE +ArticleConstants.DEFAULT_TAG);
        changeRedis(ArticleConstants.HOT_ARTICLE_FIRST_PAGE +ArticleConstants.DEFAULT_TAG,sorce,apArticle,articleStrAll);

    }

    private void changeRedis(String s, Integer sorce, ApArticle apArticle, String articleStr) {
        if (StringUtils.isNotBlank(articleStr)) {
            boolean flag =true;
            List<HotArticleVo> hotArticleVoList = JSON.parseArray(articleStr, HotArticleVo.class);
            for (HotArticleVo hotArticleVo : hotArticleVoList) {
                if (hotArticleVo.getId().equals(apArticle.getId())) {
                    hotArticleVo.setScore(sorce);
                   flag= false;
                    break;
                }
            }
            if (flag && articleStr.length() >= 30) {
                hotArticleVoList.sort((o1, o2) -> o2.getScore() - o1.getScore());
                HotArticleVo lastArticle = hotArticleVoList.get(hotArticleVoList.size() - 1);
                if (lastArticle.getScore() < sorce) {
                    hotArticleVoList.remove(lastArticle);
                    HotArticleVo hotArticleVo = new HotArticleVo();
                    BeanUtils.copyProperties(apArticle, hotArticleVo);
                    hotArticleVo.setScore(sorce);


                    hotArticleVoList.add(hotArticleVo);
                }

            } else if (flag){
                HotArticleVo hotArticleVo = new HotArticleVo();
                BeanUtils.copyProperties(apArticle, hotArticleVo);
                hotArticleVo.setScore(sorce);
                hotArticleVoList.add(hotArticleVo);
            }
            redisTemplate.opsForValue().set(s,JSON.toJSONString(hotArticleVoList));
        }
    }


    /**
     * 重新计算分数
     * @param apArticle
     * @return
     */
    private Integer changeSorce(ApArticle apArticle) {
        Integer sorce = 0;
        if (apArticle.getViews() != null) {
            sorce+=apArticle.getViews();
        }
        if (apArticle.getCollection() != null) {
            sorce+=apArticle.getCollection()*ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        if (apArticle.getComment() != null) {
            sorce+=apArticle.getComment()*ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if (apArticle.getLikes() != null) {
            sorce+=apArticle.getLikes()*ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        return sorce;
    }

    @Override
    public ResponseResult load2(Short loadtype, ArticleHomeDto dto, boolean firstPage) {
        if (firstPage) {
            String result = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
            if (StringUtils.isNotBlank(result)) {
                List<HotArticleVo> hotArticleVoList = JSON.parseArray(result, HotArticleVo.class);
                if (hotArticleVoList != null && hotArticleVoList.size() > 0) {
                    ResponseResult responseResult = ResponseResult.okResult(hotArticleVoList);
                    responseResult.setHost(fileServerUrl);
                    return responseResult;
                }
            }
        }
       return loadArticleList(dto,loadtype);
    }
}